package coordination

import (
	"context"
	"fmt"
	"log"
	"os"
	"sync"
	"time"

	"github.com/louloulin/dataflare/pkg/cluster"
)

// LeaderElection 是领导者选举接口
type LeaderElection interface {
	// Start 启动领导者选举
	Start(ctx context.Context) error
	// Stop 停止领导者选举
	Stop(ctx context.Context) error
	// IsLeader 检查是否为领导者
	IsLeader(ctx context.Context) (bool, error)
	// WaitForLeadership 等待成为领导者
	WaitForLeadership(ctx context.Context) error
	// GetLeader 获取当前领导者
	GetLeader(ctx context.Context) (*cluster.NodeInfo, error)
	// OnLeadershipChange 设置领导权变更回调
	OnLeadershipChange(callback func(isLeader bool))
}

// ClusterLeaderElection 是基于集群的领导者选举
type ClusterLeaderElection struct {
	// manager 是集群管理器
	manager cluster.Manager
	// electionKey 是选举键
	electionKey string
	// leaderID 是当前领导者ID
	leaderID string
	// isLeader 表示本地节点是否为领导者
	isLeader bool
	// leadershipCallback 是领导权变更回调
	leadershipCallback func(isLeader bool)
	// mu 是保护状态的互斥锁
	mu sync.RWMutex
	// logger 是日志记录器
	logger *log.Logger
	// ctx 是上下文
	ctx context.Context
	// cancel 是取消函数
	cancel context.CancelFunc
}

// NewClusterLeaderElection 创建一个新的基于集群的领导者选举
func NewClusterLeaderElection(manager cluster.Manager, electionKey string) LeaderElection {
	// 创建上下文
	ctx, cancel := context.WithCancel(context.Background())

	return &ClusterLeaderElection{
		manager:     manager,
		electionKey: electionKey,
		logger:      log.New(os.Stderr, "[LeaderElection] ", log.LstdFlags),
		ctx:         ctx,
		cancel:      cancel,
	}
}

// Start 启动领导者选举
func (e *ClusterLeaderElection) Start(ctx context.Context) error {
	e.logger.Println("Starting leader election")

	// 订阅集群事件
	eventCh, err := e.manager.Subscribe(ctx, cluster.EventTypeClusterChanged)
	if err != nil {
		return fmt.Errorf("failed to subscribe to cluster events: %w", err)
	}

	// 启动选举循环
	go e.electionLoop(eventCh)

	// 立即进行一次选举
	err = e.runElection(ctx)
	if err != nil {
		e.logger.Printf("Initial election failed: %v", err)
		// 继续运行，不返回错误
	}

	return nil
}

// Stop 停止领导者选举
func (e *ClusterLeaderElection) Stop(ctx context.Context) error {
	e.logger.Println("Stopping leader election")

	// 取消上下文
	e.cancel()

	return nil
}

// IsLeader 检查是否为领导者
func (e *ClusterLeaderElection) IsLeader(ctx context.Context) (bool, error) {
	e.mu.RLock()
	defer e.mu.RUnlock()

	return e.isLeader, nil
}

// WaitForLeadership 等待成为领导者
func (e *ClusterLeaderElection) WaitForLeadership(ctx context.Context) error {
	// 检查是否已经是领导者
	isLeader, _ := e.IsLeader(ctx)
	if isLeader {
		return nil
	}

	// 创建通道
	leaderCh := make(chan struct{})
	var once sync.Once

	// 设置回调
	oldCallback := e.leadershipCallback
	e.leadershipCallback = func(isLeader bool) {
		// 调用旧回调
		if oldCallback != nil {
			oldCallback(isLeader)
		}

		// 如果成为领导者，关闭通道
		if isLeader {
			once.Do(func() {
				close(leaderCh)
			})
		}
	}

	// 等待成为领导者或上下文取消
	select {
	case <-leaderCh:
		return nil
	case <-ctx.Done():
		return ctx.Err()
	}
}

// GetLeader 获取当前领导者
func (e *ClusterLeaderElection) GetLeader(ctx context.Context) (*cluster.NodeInfo, error) {
	e.mu.RLock()
	defer e.mu.RUnlock()

	// 检查是否有领导者
	if e.leaderID == "" {
		return nil, fmt.Errorf("no leader elected")
	}

	// 获取领导者节点
	return e.manager.GetNode(ctx, e.leaderID)
}

// OnLeadershipChange 设置领导权变更回调
func (e *ClusterLeaderElection) OnLeadershipChange(callback func(isLeader bool)) {
	e.mu.Lock()
	defer e.mu.Unlock()

	e.leadershipCallback = callback
}

// electionLoop 选举循环
func (e *ClusterLeaderElection) electionLoop(eventCh <-chan cluster.Event) {
	// 创建定时器
	ticker := time.NewTicker(5 * time.Second)
	defer ticker.Stop()

	for {
		select {
		case <-e.ctx.Done():
			return
		case <-ticker.C:
			// 定期进行选举
			err := e.runElection(e.ctx)
			if err != nil {
				e.logger.Printf("Election failed: %v", err)
			}
		case event := <-eventCh:
			// 集群变更时进行选举
			e.logger.Printf("Cluster changed: %s", event.Type)
			err := e.runElection(e.ctx)
			if err != nil {
				e.logger.Printf("Election failed: %v", err)
			}
		}
	}
}

// runElection 运行选举
func (e *ClusterLeaderElection) runElection(ctx context.Context) error {
	// 获取所有节点
	nodes, err := e.manager.GetNodes(ctx)
	if err != nil {
		return fmt.Errorf("failed to get nodes: %w", err)
	}

	// 如果没有节点，返回错误
	if len(nodes) == 0 {
		return fmt.Errorf("no nodes in cluster")
	}

	// 获取本地节点
	localNode, err := e.manager.GetLocalNode(ctx)
	if err != nil {
		return fmt.Errorf("failed to get local node: %w", err)
	}

	// 选择领导者（按照节点ID排序，选择第一个）
	var leaderNode *cluster.NodeInfo
	for _, node := range nodes {
		if node.Status == cluster.NodeStatusUp {
			if leaderNode == nil || node.ID < leaderNode.ID {
				leaderNode = node
			}
		}
	}

	// 如果没有可用节点，返回错误
	if leaderNode == nil {
		return fmt.Errorf("no available nodes")
	}

	e.mu.Lock()
	defer e.mu.Unlock()

	// 更新领导者
	oldLeaderID := e.leaderID
	e.leaderID = leaderNode.ID

	// 更新领导者状态
	oldIsLeader := e.isLeader
	e.isLeader = (leaderNode.ID == localNode.ID)

	// 如果领导者变更，调用回调
	if oldLeaderID != e.leaderID || oldIsLeader != e.isLeader {
		e.logger.Printf("Leader changed: %s -> %s", oldLeaderID, e.leaderID)
		if e.leadershipCallback != nil {
			e.leadershipCallback(e.isLeader)
		}
	}

	return nil
}
